package cate.game.db.facade;

import cate.game.GameBody;
import cate.game.db.mongo.kv.KvMongo;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class KvLoader<T extends KvMongo> {

    private GameBody game;
    private Class<T> kvClz;
    private String keyPrefix;

    public KvLoader(GameBody game, Class<T> kvClz, String keyPrefix) {
        this.game = game;
        this.kvClz = kvClz;
        this.keyPrefix = keyPrefix;
    }

    /** 最终结果值 */
    private T finalData;

    private List<T> olds;

    private T buildInitValue() {
        try {
            T v = this.kvClz.getDeclaredConstructor().newInstance();
            return v;
        } catch (Exception e) {
            log.error("", e);
            return null;
        }
    }

    private List<T> getAll() {
        this.olds = game.db.kv.findByKeyPrefix(keyPrefix, this.kvClz);
        return this.olds;
    }

    /** 获取kv数据
     * 策略：使用自定义方法合并数据 */
    public T getWithMerge(KvMerger<T> merger) {
        List<T> dataList = getAll();
        this.finalData = merger.merge(dataList);
        deleteOldsAndSaveFinal();
        return this.finalData;
    }

    /** 获取kv数据
     * 策略：选择第一个（相当于任选其中一个） */
    public T getFirst() {
        List<T> dataList = getAll();
        if(dataList != null && !dataList.isEmpty()) {
            this.finalData = dataList.get(0);
        } else {
            this.finalData = buildInitValue();
        }
        deleteOldsAndSaveFinal();
        return this.finalData;
    }

    /** 获取kv数据
     * 策略：选择匹配srvId的数据 */
    public T getBySrvId() {
        return getBySrvId(false);
    }

    /** 获取kv数据
     * 策略：选择匹配srvId的数据
     * @param useFirstWhenNotMatch 当没有匹配srvId的数据时，选择第一个 */
    public T getBySrvId(boolean useFirstWhenNotMatch) {
        List<T> dataList = getAll();
        if(dataList == null || dataList.isEmpty()) {
            this.finalData = buildInitValue();
        } else {
            for(T data : dataList) {
                if(data.srvId == game.config.srvId) {
                    this.finalData = data;
                    break;
                }
            }
        }
        if(this.finalData == null) {
            if (useFirstWhenNotMatch) {
                this.finalData = dataList.get(0);
            } else {
                this.finalData = buildInitValue();
            }
        }
        deleteOldsAndSaveFinal();
        return this.finalData;
    }

    private void deleteOldsAndSaveFinal() {
        if(olds != null) {
            for(T old : olds) {
                if(old != null) {
                    game.db.kv.delete(old.key);
                }
            }
        }
        this.finalData.initialize();
        game.db.kv.save(this.finalData);
    }

}
